iT邦幫忙

2025 iThome 鐵人賽

DAY 3
0
AI & Data

咖狗報到-30天玩轉Kaggle競賽系列 第 3

一起來參加Kaggle競賽-提升實戰經驗(探索式資料分析 ,EDA)

  • 分享至 

  • xImage
  •  

昨天我們理解了比賽的任務、評分方式,並完成資料解壓與前處理。今天,我們要進一步了解資料的分布與特徵,這一步叫做探索式資料分析(Exploratory Data Analysis, EDA)


1. 檢視數值型欄位分布

首先我們用 describe() 來快速檢查數值欄位的統計資訊:

display(train.describe())

https://ithelp.ithome.com.tw/upload/images/20250914/20161909BqYh53Opcy.png

欄位 觀察
age 年齡範圍 18–95 歲,平均 40 歲,中位數 39 歲
balance 有負值(最低 -8019),代表欠款或透支狀態,中位數是 634
day 分布在 1–31,一個月就是1-31天合理
duration 平均通話 256 秒,中位數 133 秒,但最大值到 4918 秒
campaign 通常聯絡次數 1–3 次,最大值 63 次,可能是極端值,需要注意
pdays pdays 在這個資料集中指的是距離客戶上一次被聯絡的天數,如果 pdays = -1,表示這個客戶之前從未被聯絡過。pdays = 30 → 上次聯絡是 30 天前,以此類推
previous 大部分都是 0(沒有先前行銷紀錄)
y 只有 12% 的客戶有申請定存,是一個明顯不平衡的分類問題

接著我們把圖畫出來看看數值的分布

import matplotlib.pyplot as plt

train.hist(figsize=(15, 10))
plt.tight_layout()
plt.show()

透過這些直方圖,我們可以發現數值是否集中在某一區間,或是極端值很多
https://ithelp.ithome.com.tw/upload/images/20250914/20161909jJC6oBEOeY.png

2. 檢視類別型欄位分布

接著檢查類別欄位出現次數,確認是否有明顯不平衡,首先會先把這一欄(例如:年齡)裡每一種不同的值(18-95歲)各自出現的次數去做計算,接下來用normalize=True算成比例(出現次數 ÷ 總筆數),然後把<5% 歸類到非常不平衡,<10% 歸類到可能不平衡。

categorical_cols = train.select_dtypes(include=['object', 'category']).columns

for col in categorical_cols:
    print(f"=== Column: {col} ===")
    counts = train[col].value_counts()
    ratios = train[col].value_counts(normalize=True)

    for category, count in counts.items():
        ratio = ratios[category]
        flag = ""
        if ratio < 0.05:
            flag = "<5% (非常不平衡)"
        elif ratio < 0.10:
            flag = "<10% (可能不平衡)"
        print(f"{category}: {count} ({ratio:.2%}) {flag}")
    print("-" * 40)

接下來我們要特別觀察要預測的目標欄位,在這次的競賽中目標欄位是y,(內容通常是 "yes" 或 "no"或是"1"或"0"),代表客戶是否有定期存款(term deposit),也就是說,我們需要建立一個模型,根據客戶的特徵(年齡、工作、婚姻、貸款狀態、通話紀錄…),去預測他們最終到底會不會去銀行定期存款。

print(train['y'].value_counts(normalize=True))

https://ithelp.ithome.com.tw/upload/images/20250916/20161909n4fwTx8tTU.png

到這邊你會發現,沒有定期存款的大約是0.88,有定期存款的是0.12,這是一個類別不平衡的現象,我們需要處理它。而你可能會好奇,可能會覺得它就是我們要預測的最終答案啦,為什麼即使這樣,還需要在訓練時針對目標(target)去處理不平衡問題呢?

首先我們可以想成:如果模型什麼都不學,只要永遠預測 no,就會得到一個準確率 = 88%「準確度高」的模型(因為 88% 的人真的說 no),但這真的是一個「好」模型嗎?

模型會完全找不到任何會說 yes 的人! 很顯然這樣的模型不會是一個好模型,這個模型可以說是完全沒有用。為什麼沒有用呢?因為在我們今天的題目,對銀行來說,要找出可能會答應定期存款的人(yes)才有價值,所以如果模型只會預測 no,就浪費了行銷機會。

3. 觀察特徵與目標的關係

在做特徵工程的時候,我們常常要先問自己一個問題:
「哪些特徵真的跟我要預測的東西有關?」
因為如果把一堆沒用的特徵丟進去,模型可能會學到一些奇怪的規則,最後不但沒有比較好,還可能更差。

所以對於類別型變數,我們可以用 groupby 來計算每個類別中,目標變數是「有定期存款」(y=1)的比例。這個比例就叫做轉換率(Conversion Rate)。舉個例子:如果職業欄位裡有 200 個「上班族」,其中有 60 個人最後成功購買,那上班族的轉換率就是 60 ÷ 200 = 30%。這個數字告訴我們,上班族比其他類別更容易被轉換成「買單的客戶」。

用這種方法,我們就能觀察哪些特徵跟目標變數有關,像是不同的職業、婚姻狀態、教育程度,會不會對「成功行銷」的機率有影響,而這些特徵就是我們後面建模的重要線索。

import pandas as pd
import matplotlib.pyplot as plt

# 取得所有類別型欄位
categorical_cols = train.select_dtypes(include=['object', 'category']).columns

for col in categorical_cols:
    # 計算每個類別中 y=1 的比例(轉換率)
    crosstab = pd.crosstab(train[col], train['y'], normalize='index')
    
    # 取出 y=1 的比例並排序
    yes_rate = crosstab.get(1, pd.Series(dtype=float)).sort_values(ascending=False)

    print(f"=== {col} ===")
    print(yes_rate)
    print("-" * 40)

    # 畫出長條圖
    yes_rate.plot(
        kind='bar',
        title=f"{col} vs Conversion Rate (Yes)",
        ylabel="Conversion Rate",
        xlabel=col,
    )
    plt.xticks(rotation=45)
    plt.tight_layout()
    plt.show()

https://ithelp.ithome.com.tw/upload/images/20250916/20161909EA1zSxgLPc.png

不同婚姻狀態對定期存款的影響。可以看到單身族群的轉換率明顯比已婚、離婚都高,這或許說明單身的人對金融產品更有興趣?
https://ithelp.ithome.com.tw/upload/images/20250916/201619093ZFBZLIymA.png
不同職業的轉換率差異更明顯,學生和退休族的轉換率最高,而藍領族群和企業家反而最低,這對後續行銷策略就很有參考價值。

4. 結語

今天把各類別特徵和目標變數的關係都畫出來,也觀察到一些有趣的現象:像是單身族群的轉換率最高、學生和退休族的行銷成功率也很高。

明天我就要開始訓練最基本的 Baseline 模型,看看不用做太多特徵工程的情況下模型能到什麼水準,之後再根據今天的觀察結果來做特徵微調,逐步提升模型表現。


上一篇
一起來參加Kaggle競賽-提升實戰經驗(認識比賽+資料前處理)
系列文
咖狗報到-30天玩轉Kaggle競賽3
圖片
  熱門推薦
圖片
{{ item.channelVendor }} | {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言